#include "SystemInfo.h"
#include <cstdio>
#include <linux/fs.h>
#include <fcntl.h>
#include <unistd.h>
#include <string>
#include <fstream>
#include <time.h>
#include <iostream>
#include <iomanip>
#include "sys/vfs.h"
using namespace std;

namespace MC500
{

    TrifficInfo ReadCurrentTrifficCount(const string &portName)
    {
        ifstream trifficInfoStream("/proc/net/dev", ios_base::in);
        string skipLine;
        getline(trifficInfoStream, skipLine);
        getline(trifficInfoStream, skipLine);
        string currPortName;
        uint64_t upstream = 0;
        uint64_t downstream = 0;
        uint64_t skipData;
        while (trifficInfoStream >> currPortName >> upstream >> skipData >>
               skipData >> skipData >> skipData >> skipData >> skipData >>
               skipData >> downstream >> skipData >> skipData >> skipData >>
               skipData >> skipData >> skipData >> skipData)
        {
            if (currPortName == portName + ":")
            {
                return TrifficInfo(upstream, downstream);
            }
        }
        cout << "Port name not found!PortName=" << currPortName << endl;
        return TrifficInfo(0, 0);
    }

    struct MemInfo
    {
        uint64_t total;
        uint64_t free;
    } memInfo_;

    void GetMemInfo()
    {

        memInfo_.total = 0;
        memInfo_.free = 0;

        ifstream meminfoInputStream("/proc/meminfo", ios_base::in);
        string name;
        uint64_t value;
        string unit;
        while (meminfoInputStream >> name >> value >> unit)
        {
            if (name == "MemTotal:")
            {
                memInfo_.total = value;
            }
            else if (name == "MemFree:")
            {
                memInfo_.free = value;
            }

            if (memInfo_.total != 0 && memInfo_.free != 0)
            {
                return;
            }
        }
        memInfo_.total = 1;
    }
    struct CPUInfo
    {
        uint64_t userTime;
        uint64_t niceTime;
        uint64_t systemTime;
        uint64_t idleTIme;
    };
    void ReadCpuInfo(FILE *fd, CPUInfo &info)
    {
        char buff[256];
        memset(buff, '\0', 256);
        char *ret = fgets(buff, sizeof(buff), fd);
        if (ret == NULL)
        {
            return;
        }
        char cpuName[128];
        sscanf(buff, "%s %lu %lu %lu %lu", cpuName, &info.userTime, &info.niceTime,
               &info.systemTime, &info.idleTIme);
    }

    uint64_t SystemInfo::GetPhyMem(void)
    {
        GetMemInfo();
        return memInfo_.total;
    }

    uint64_t SystemInfo::GetPhyMemUsed(void)
    {
        GetMemInfo();
        return memInfo_.total - memInfo_.free;
    }

    uint8_t SystemInfo::GetCPUUsed(void)
    {
        FILE *fd = fopen("/proc/stat", "r");
        CPUInfo info[2];
        ReadCpuInfo(fd, info[0]);
        usleep(1000);
        ReadCpuInfo(fd, info[1]);
        fclose(fd);

        uint64_t timeInUse = (info[1].userTime - info[0].userTime) + (info[1].systemTime - info[0].systemTime) + (info[1].userTime - info[0].userTime);
        uint64_t timeTotal = timeInUse + (info[1].idleTIme - info[0].idleTIme);
        if (timeTotal == 0)
        {
            timeTotal = 1;
        }

        return (timeInUse * 100) / timeTotal;
    }
    DateTime SystemInfo::GetDateTime()
    {
        time_t tt;
        time(&tt);
        tt = tt + 8 * 3600; // transform the time zone
        tm *t = gmtime(&tt);
        DateTime date = {t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec};
        return date;
    }
    DateTime SystemInfo::GetStableRunningTime()
    {
        DateTime date = {2020, 1, 30, 18, 5, 11};
        return date;
    }
    TrifficInfo SystemInfo::GetTrifficInfo(const string &portName)
    {
        TrifficInfo triffic1 = ReadCurrentTrifficCount(portName);
        usleep(50000);
        TrifficInfo triffic2 = ReadCurrentTrifficCount(portName);

        return TrifficInfo((triffic2.uploadSpeed - triffic1.uploadSpeed) * 20,
                           (triffic2.downloadSpeed - triffic1.downloadSpeed) * 20);
    }

    uint8_t SystemInfo::GetDiskUsage(const string &partition)
    {
        struct statfs partitionInfo;
        statfs(partition.c_str(), &partitionInfo);
        if (partitionInfo.f_blocks == 0)
        {
            return 0;
        }
        return ((partitionInfo.f_bsize - partitionInfo.f_bfree) * 100) / partitionInfo.f_bsize;
    }

} // namespace MC500